// import {
// 	Clock,
// 	HalfFloatType,
// 	NoBlending,
// 	Vector2,
// 	WebGLRenderTarget
// } from 'three';
// import { CopyShader } from '../shaders/CopyShader.js';
import { CopyShader } from './CopyShader';
import { ShaderPass, setThreeAPI as setThreeAPIForShaderPass } from './ShaderPass.js';
import { MaskPass } from './MaskPass.js';
import { ClearMaskPass } from './MaskPass.js';

import { setThreeAPI as setThreeAPIForPass } from './Pass.js';
import { setThreeAPI as setThreeAPIForRenderPass } from './RenderPass';
import { setThreeAPI as setThreeAPIForOutlinePass } from './OutlinePass';

let Clock,
	HalfFloatType,
	NoBlending,
	Vector2,
	WebGLRenderTarget


export let setThreeAPI = (threeAPIObj) => {
	Clock = threeAPIObj.Clock
	HalfFloatType = threeAPIObj.HalfFloatType
	NoBlending = threeAPIObj.NoBlending
	Vector2 = threeAPIObj.Vector2
	WebGLRenderTarget = threeAPIObj.WebGLRenderTarge

	setThreeAPIForShaderPass(threeAPIObj)
	setThreeAPIForPass(threeAPIObj)
	setThreeAPIForRenderPass(threeAPIObj)
	setThreeAPIForOutlinePass(threeAPIObj)
}


class EffectComposer {

	constructor(renderer, renderTarget) {
		this.renderer = renderer;

		this._pixelRatio = renderer.getPixelRatio();

		if (renderTarget === undefined) {

			const size = renderer.getSize(new Vector2());
			this._width = size.width;
			this._height = size.height;

			renderTarget = new WebGLRenderTarget(this._width * this._pixelRatio, this._height * this._pixelRatio, { type: HalfFloatType });
			renderTarget.texture.name = 'EffectComposer.rt1';

		} else {

			this._width = renderTarget.width;
			this._height = renderTarget.height;

		}

		this.renderTarget1 = renderTarget;
		this.renderTarget2 = renderTarget.clone();
		this.renderTarget2.texture.name = 'EffectComposer.rt2';

		this.writeBuffer = this.renderTarget1;
		this.readBuffer = this.renderTarget2;

		this.renderToScreen = true;

		this.passes = [];

		this.copyPass = new ShaderPass(CopyShader);
		this.copyPass.material.blending = NoBlending;

		this.clock = new Clock();

	}

	swapBuffers() {

		const tmp = this.readBuffer;
		this.readBuffer = this.writeBuffer;
		this.writeBuffer = tmp;

	}

	addPass(pass) {

		this.passes.push(pass);
		pass.setSize(this._width * this._pixelRatio, this._height * this._pixelRatio);

	}

	insertPass(pass, index) {

		this.passes.splice(index, 0, pass);
		pass.setSize(this._width * this._pixelRatio, this._height * this._pixelRatio);

	}

	removePass(pass) {

		const index = this.passes.indexOf(pass);

		if (index !== - 1) {

			this.passes.splice(index, 1);

		}

	}

	isLastEnabledPass(passIndex) {

		for (let i = passIndex + 1; i < this.passes.length; i++) {

			if (this.passes[i].enabled) {

				return false;

			}

		}

		return true;

	}

	render(deltaTime) {

		// deltaTime value is in seconds

		if (deltaTime === undefined) {

			deltaTime = this.clock.getDelta();

		}

		const currentRenderTarget = this.renderer.getRenderTarget();

		let maskActive = false;

		for (let i = 0, il = this.passes.length; i < il; i++) {

			const pass = this.passes[i];

			if (pass.enabled === false) continue;

			pass.renderToScreen = (this.renderToScreen && this.isLastEnabledPass(i));
			pass.render(this.renderer, this.writeBuffer, this.readBuffer, deltaTime, maskActive);

			if (pass.needsSwap) {

				if (maskActive) {

					const context = this.renderer.getContext();
					const stencil = this.renderer.state.buffers.stencil;

					//context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );
					stencil.setFunc(context.NOTEQUAL, 1, 0xffffffff);

					this.copyPass.render(this.renderer, this.writeBuffer, this.readBuffer, deltaTime);

					//context.stencilFunc( context.EQUAL, 1, 0xffffffff );
					stencil.setFunc(context.EQUAL, 1, 0xffffffff);

				}

				this.swapBuffers();

			}

			if (MaskPass !== undefined) {

				if (pass instanceof MaskPass) {

					maskActive = true;

				} else if (pass instanceof ClearMaskPass) {

					maskActive = false;

				}

			}

		}

		this.renderer.setRenderTarget(currentRenderTarget);

	}

	reset(renderTarget) {

		if (renderTarget === undefined) {

			const size = this.renderer.getSize(new Vector2());
			this._pixelRatio = this.renderer.getPixelRatio();
			this._width = size.width;
			this._height = size.height;

			renderTarget = this.renderTarget1.clone();
			renderTarget.setSize(this._width * this._pixelRatio, this._height * this._pixelRatio);

		}

		this.renderTarget1.dispose();
		this.renderTarget2.dispose();
		this.renderTarget1 = renderTarget;
		this.renderTarget2 = renderTarget.clone();

		this.writeBuffer = this.renderTarget1;
		this.readBuffer = this.renderTarget2;

	}

	setSize(width, height) {

		this._width = width;
		this._height = height;

		const effectiveWidth = this._width * this._pixelRatio;
		const effectiveHeight = this._height * this._pixelRatio;

		this.renderTarget1.setSize(effectiveWidth, effectiveHeight);
		this.renderTarget2.setSize(effectiveWidth, effectiveHeight);

		for (let i = 0; i < this.passes.length; i++) {

			this.passes[i].setSize(effectiveWidth, effectiveHeight);

		}

	}

	setPixelRatio(pixelRatio) {

		this._pixelRatio = pixelRatio;

		this.setSize(this._width, this._height);

	}

	dispose() {

		this.renderTarget1.dispose();
		this.renderTarget2.dispose();

		this.copyPass.dispose();

	}

}

export { EffectComposer };
